/**
 * 逻辑公式服务
 * 逻辑公式: 即表格的结构以及数据通过具体的业务逻辑（定义相关的业务解析器）
 * 1. 提供表格公式扫描检索
 * 2. 提供注册公式运行机制
 * 3. 提供全表公式运算, 支持多逻辑公式顺序运算。下一个公式的运算依赖上一个公式的运算结果
 * 4. 设置行/列级别的逻辑公式
 * 公式存储和公式状态:
 * 1.公式以及公式状态存储在行/列的配置中
 * 2.公式状态分为 ready , finish  ready表示公式待执行，表示公式已经执行。当遇到finish状态的公式时，不再执行公式.
 */
export default class LogicFormulaService {
    context;
    //存储注册的行公式和解析器:例如 {"name":"Dr" , parse: parseDrFormula}
    formulaMap = new Map();
    // //存储扫描到的待待执行公式:例如 {"Dr":[{row:"1",params:["a","b"],state:"ready"},{row:"3",params:["c","d"],"state":"finish"}] , "Dc":[{col:"2",params:["e","f"],state:"ready"},{col:"4",params:["g","h"],state:"ready"}]
    // private formulaScanMap = new Map();
    //声明公式执行队列
    // [{row:"1",params:["a","b"],state:"ready",name:"Dr"},{row:"3",params:["c","d"],"state":"",name:"Dr"}] , "Dc":[{col:"2",params:["e","f"],state:"ready",name:"Dc"},{col:"4",params:["g","h"],state:"ready",name:"Dc"}
    formulaQueue = [];
    constructor(context) {
        this.context = context;
    }
    get headerService() {
        return this.context.headerService;
    }
    get hot() {
        return this.context.hot;
    }
    get hyper() {
        return this.context.hyper;
    }
    get gridService() {
        return this.context.gridService;
    }
    destroy() {
        this.context = null;
    }
    // 根据行列索引号解析，当前单元格是否是 matchDynamic 的单元格
    isMatchDynamicPosition(rowIndex, colIndex, formula) {
        let formulaType = "";
        if (formula.startsWith("Dr")) {
            formulaType = "Dr";
        }
        else if (formula.startsWith("Dc")) {
            formulaType = "Dc";
        }
        else {
            return false;
        }
        const formulaInfo = LogicFormulaService.parseLogicFormula(formulaType, formula);
        // 如果是动态行，则检测当前列的索引号是否和公式中的映射一致
        let map;
        if (formulaType === "Dr") {
            map = formulaInfo.rowDevCpasMap;
            return map.some((obj) => obj.cpasIndex === colIndex);
        }
        else if (formulaType === "Dc") {
            // 如果是动态列，则检测当前行的rmap是否存在映射关系中.
            map = formulaInfo.cDevCpasMap;
            return map.some((obj) => obj.cpasIndex === rowIndex);
        }
        return false;
    }
    // 封装一个共用方法：编辑行列动态公式
    static parseLogicFormula(type, formula) {
        // console.log("333--logicFormulaService", type, formula);
        if (type === "Dc") {
            // 列动态
            if (formula) {
                let cTypes = formula.slice(0, 2);
                let first = formula?.split("|||");
                let secFir = first[1].split(",");
                let devCpasMap = first[1].slice(0, -1); // 两表关系映射
                let cDevCpasMap = eval(devCpasMap); // 反转的两表关系
                let first0 = JSON.parse(first[0].substr(3)); // 附加条件 和表头 fields,where
                // console.log("333---列动态编辑公式", first0, cDevCpasMap);
                return { first0, cDevCpasMap };
            }
        }
        else if (type === "Dr") {
            // 行动态
            if (formula) {
                let cTypes = formula.slice(0, 2);
                let first = formula?.split("|||");
                let secFir = first[1].split(",");
                let devCpasMap = first[1].slice(0, -1); // 两表关系映射
                let rowDevCpasMap = eval(devCpasMap); // 反转的两表关系
                let first0 = JSON.parse(first[0].substr(3)); // 附加条件 和表头 fields,where
                console.log("333---行动态编辑公式", first0, rowDevCpasMap);
                return { first0, rowDevCpasMap };
            }
        }
        return {};
    }
    //注册自定义行公式,例如 Dr(params1:string,params2:string)
    registerFormula(name, formula) {
        //存储自定义公式以及解析器
        this.formulaMap.set(name, formula);
    }
    //扫描所有行数据，获取行公式
    scanFormula(iGridData) {
        let count = 0;
        //清空公式任务队列
        this.formulaQueue.length = 0;
        //1.获取所有行数据
        let gridData;
        let headerColumns;
        if (iGridData) {
            gridData = iGridData.data;
            headerColumns = this.headerService.getHeaderColumn(iGridData.header); // 需要根据headJson计算一下
        }
        else {
            gridData = this.context.data;
            headerColumns = this.context.headerService.headerColumn;
        }
        //2.获取所有行具体公式
        for (let i = 0; i < gridData.length; i++) {
            // const row = gridData[i];
            if (this.setFormulaScanMaps("row", i, iGridData)) {
                count++;
            }
        }
        //3. 获取所有列具体公式
        for (let i = 0; i < headerColumns.length; i++) {
            if (this.setFormulaScanMaps("column", i, iGridData)) {
                count++;
            }
        }
        return count;
    }
    //根据行号获取行公式
    //从业务需求上限制每个行/列只允许具备一个行公式
    //任何状态的公式扫描到都进行存储
    setFormulaScanMaps(type, index, iGridData) {
        let formula = "";
        let formulaState = "ready";
        //1.获取行公式
        if (type === "row") {
            const config = this.context.gridService.getRowMeteDataByRow(index, iGridData ? iGridData.data : null);
            formula = config.formula;
            formulaState = config.formulaState || "ready";
        }
        else {
            const node = this.context.headerService.getHeaderConfigByIndex(iGridData ? iGridData.header : this.context.headerService.headJson, index);
            formula = node.config.formula;
            formulaState = node.config.formulaState || "ready";
        }
        if (!formula) {
            return false;
        }
        //2.解析公式名称,行号,公式参数  例如 Dr(1,2)  name:Dr,row:1,params:[1,2],state:ready
        const { name, params } = this.parseFormula(formula);
        //3. 公式入队 例如 [{name:"Dr",row:1,params:[1,2],state:ready},{name:"Dr",row:3,params:[3,4],state:ready}]
        this.formulaQueue.push({
            name,
            type,
            index,
            params: params,
            state: formulaState,
        });
        return true;
    }
    //解析公式根据字符串获取公式名称,行号,公式参数
    parseFormula(formula) {
        //1.获取公式名称
        //编写提取函数名的代码,例如Dr(1,2) 返回Dr字符串
        const name = formula.substring(0, formula.indexOf("("));
        //2.获取公式参数
        //生成替换左右括号为空的正则表达式，用replace方法替换掉左右括号
        const reg = new RegExp(/[\(\)]/g);
        const params = formula
            .substring(formula.indexOf("("))
            .replace(reg, "")
            .split("|||");
        const parseParams = params.map((item) => {
            return JSON.parse(item);
        });
        //3.获取行号
        return {
            name: name,
            params: parseParams,
        };
    }
    //检索formulaScanMap中的行公式，执行行公式
    async executeLogicFormula(iGirdData) {
        if (this.formulaQueue.length === 0) {
            return null;
        }
        let lastLogicData;
        //如果外部传入了iGridData则表示外部需要获取公式计算后的数据，否则使用内部的数据
        if (iGirdData) {
            lastLogicData = iGirdData;
        }
        else if (this.context.hot) {
            //如果不是外部传入的数据，则使用内部的数据. hot如果已经初始化好了则通过getCpasTableGrid获取最新数据
            lastLogicData = this.context.getCpasTableGrid();
        }
        else {
            //如果hot还没有初始化好，则使用默认初始化数据
            lastLogicData = {
                data: this.context.data,
                header: this.context.headerService.headJson,
                cellsMeta: this.context.cellMetaData,
                tableConfig: this.context.tableConfig,
            };
        }
        //1.遍历具体行公式,并执行相应的解析器
        while (this.formulaQueue.length > 0) {
            //获取队头公式
            const { name, params, state, index, type } = this.formulaQueue.shift();
            //根据公式名称获取公式类型
            const formula = this.formulaMap.get(name);
            //2.执行公式, state为ready时执行公式
            if (formula && state === "ready") {
                try {
                    const position = await formula(type, index, params, lastLogicData, this.context);
                    //3.设置公式状态为finish , 刷新cellsMeta
                    this.setFormulaState(type, index, "finish", lastLogicData, position);
                    //更新公式队列中的索引号
                    this.updateFormulaQueueIndexByDynamicPosition(position);
                }
                catch (e) {
                    throw e;
                }
            }
        }
        return lastLogicData;
    }
    //清空matchDycimal标记
    clearMatchDynamic(iGridData) {
        const { data, header } = iGridData;
        for (let i = 0; i < data.length; i++) {
            const row = data[i];
            const row_config_str = row[row.length - 1];
            const config = JSON.parse(row_config_str);
            if (config && config["matchDynamic"]) {
                delete config["matchDynamic"];
            }
            row[row.length - 1] = JSON.stringify(config);
        }
        function findNodeByKeyIteration(headJson) {
            for (let i = 0; i < headJson.length; i++) {
                const node = headJson[i];
                if (node.children) {
                    findNodeByKeyIteration(node.children);
                }
                if (node.config && node.config["matchDynamic"]) {
                    delete node.config["matchDynamic"];
                }
            }
        }
        findNodeByKeyIteration(header);
        return iGridData;
    }
    //获取isDynamic为true的行/列
    getDynamicRowsOrColumns(type, iGridData = null, isClearFormula) {
        //此处接收的可能只是逻辑公式执行后的数据，所以需要判断是否传入了iGridData。 并没有真实的刷新表格
        const { header, data } = iGridData;
        const dynamicRowsOrColumns = [];
        if (type === "row") {
            const gridData = data || this.context.data;
            for (let i = 0; i < gridData.length; i++) {
                const config = this.gridService.getRowMeteDataByRow(i, gridData);
                if (config.isDynamic && !config.formula) {
                    dynamicRowsOrColumns.push(i);
                }
                else if (config.formula) {
                    for (let j = 0; j < gridData[i].length - 1; j++) {
                        gridData[i][j] = null;
                    }
                    gridData[i][0] = "...";
                    gridData[i][1] = "...";
                    if (isClearFormula === true) {
                        delete config.formula;
                        delete config.isDynamic;
                        delete config.formulaState;
                    }
                    else {
                        delete config.isDynamic;
                        config.formulaState = "ready";
                    }
                    gridData[i][gridData[i].length - 1] = JSON.stringify(config);
                }
            }
        }
        else {
            const headerColumns = this.context.headerService.getHeaderColumn(header);
            for (let i = 0; i < headerColumns.length; i++) {
                const column = headerColumns[i];
                if (column.config.isDynamic && !column.config.formula) {
                    dynamicRowsOrColumns.push({
                        key: column.key,
                        index: i,
                    });
                }
                else if (column.config.formula) {
                    for (let j = 0; j < data.length; j++) {
                        data[j][i] = null;
                    }
                    column.label = "...";
                    data[0][i] = "...";
                    //清空公式
                    if (isClearFormula === true) {
                        delete column.config.formula;
                        delete column.config.isDynamic;
                        delete column.config.formulaState;
                    }
                    else {
                        delete column.config.isDynamic;
                        column.config.formulaState = "ready";
                    }
                }
            }
        }
        return dynamicRowsOrColumns;
    }
    //裁剪掉isDynamic为true的行/列
    trimDynamicRowsOrColumns(type, iGridData, isClearFormula) {
        if (type === "row") {
            const dynamicRows = this.getDynamicRowsOrColumns(type, iGridData, isClearFormula);
            if (dynamicRows.length > 0) {
                //裁剪行
                iGridData.data = iGridData.data.filter((item, index) => {
                    return !dynamicRows.includes(index);
                });
                //裁剪cellsMeta
                iGridData.cellsMeta = iGridData.cellsMeta.filter((item) => {
                    const { row } = item;
                    return !dynamicRows.includes(row);
                });
                //刷新cellsMeta
                const row_start = dynamicRows[0] - 1;
                const row_offset = dynamicRows.length;
                const refreshCellsMeta = this.gridService.refreshCellsMeta("row", {
                    row_start,
                    row_offset,
                    operation: "minus",
                }, iGridData.cellsMeta, false);
                iGridData.cellsMeta = refreshCellsMeta;
            }
        }
        else {
            const dynamicColumns = this.getDynamicRowsOrColumns(type, iGridData, isClearFormula);
            //从dynamicColumns提取index数组
            const dynamicColumnsIndex = dynamicColumns.map((item) => {
                return item.index;
            });
            //裁剪列头和列数据
            if (dynamicColumns.length > 0) {
                let trimHeader = iGridData.header;
                dynamicColumns.forEach((item) => {
                    trimHeader = this.context.gridService.removeColumn(item.key, false, trimHeader).headJson;
                });
                iGridData.header = trimHeader;
                iGridData.data = this.gridService.removeColumnsData(dynamicColumnsIndex, iGridData);
                //裁剪cellsMeta
                iGridData.cellsMeta = iGridData.cellsMeta.filter((item) => {
                    const { col } = item;
                    return !dynamicColumns.includes(col);
                });
                //刷新cellsMeta
                const col_start = dynamicColumns[0].index - 1;
                const col_offset = dynamicColumns.length;
                const refreshCellsMeta = this.gridService.refreshCellsMeta("column", {
                    col_start,
                    col_offset,
                    operation: "minus",
                }, iGridData.cellsMeta, false);
                iGridData.cellsMeta = refreshCellsMeta;
            }
        }
        return iGridData;
    }
    //裁剪所有动态行/列
    trimAllDynamicRowsOrColumns(iGridData, isClearFormula) {
        let trimData = this.trimDynamicRowsOrColumns("row", iGridData, isClearFormula);
        trimData = this.trimDynamicRowsOrColumns("column", trimData, isClearFormula);
        trimData = this.clearMatchDynamic(trimData);
        return trimData;
    }
    //根据行号数组或者列号数组在配置项中标记此行/列为动态生成的行/列
    setDynamicRowsOrColumns(type, indexs, iGridData) {
        if (type === "row") {
            for (let i = 0; i < indexs.length; i++) {
                this.context.gridService.setRowConfig(indexs[i], {
                    isDynamic: 1,
                }, iGridData);
            }
        }
        else {
            for (let i = 0; i < indexs.length; i++) {
                this.context.headerService.updateHeaderConfigByIndex(iGridData ? iGridData.header : this.headerService.headJson, indexs[i], {
                    isDynamic: 1,
                });
            }
        }
    }
    //根据行号或者列号设置formulaState状态
    setFormulaState(type, index, state, iGridData, position) {
        const { start, end } = position;
        if (type === "row") {
            this.context.gridService.setRowConfig(index, {
                formulaState: state,
            }, iGridData);
            //刷新cellsMeta
            iGridData.cellsMeta = this.context.gridService.refreshCellsMetaByRow("add", start, end - start, iGridData.cellsMeta, true);
        }
        else {
            this.context.headerService.updateHeaderConfigByIndex(iGridData.header, index, {
                formulaState: state,
            });
            //刷新cellsMeta
            iGridData.cellsMeta = this.context.gridService.refreshCellsMetaByColumn("add", start, end - start, iGridData.cellsMeta, true);
        }
    }
    //接收IGridData并且重置行列公式的状态为ready
    resetFormulaStateByIGridData(iGridData) {
        const { header, data } = iGridData;
        for (let i = 0; i < data.length; i++) {
            const config = this.gridService.getRowMeteDataByRow(i, data);
            if (config.formulaState === "finish") {
                this.context.gridService.setRowConfig(i, {
                    formulaState: "ready",
                }, iGridData);
            }
        }
        const headerColumns = this.context.headerService.getHeaderColumn(header);
        for (let i = 0; i < headerColumns.length; i++) {
            const config = headerColumns[i].config;
            if (config.formulaState === "finish") {
                this.context.headerService.updateHeaderConfigByIndex(header, i, {
                    formulaState: "ready",
                }, true);
            }
        }
        return iGridData;
    }
    //设置公式到行配置中
    setRowFormula(row, formula) {
        //1.设置公式到行配置中, 2.设置公式到formulaScanMap中  3.设置公式状态为ready
        this.context.gridService.setRowConfig(row, {
            formula: formula,
            formulaState: "ready",
        });
        this.setFormulaScanMaps("row", row);
    }
    //根据DynamicPosition更新formulaQueue中公式的index行列位置
    updateFormulaQueueIndexByDynamicPosition(position) {
        const { type, start, end } = position;
        //没有位置变化，不需要更新
        if (start === end) {
            return;
        }
        const formulaQueue = this.formulaQueue;
        for (let i = 0; i < formulaQueue.length; i++) {
            const formula = formulaQueue[i];
            if (type === formula.type) {
                if (formula.index >= start) {
                    formula.index = formula.index + (end - start);
                }
            }
        }
    }
    //设置列公式到列配置中
    setColumnFormula(column, formula) {
        //1.设置公式到列配置中, 2.设置公式到formulaScanMap中  3.设置公式状态为ready
        this.context.headerService.updateHeaderConfigByIndex(this.headerService.headJson, column, {
            formula: formula,
            formulaState: "ready",
        });
        this.headerService.headerCompute(this.headerService.headJson, false, false);
        this.setFormulaScanMaps("column", column);
    }
    //扫描全表公式,并运算公式返回结果
    async scanAndExecuteAllFormula(iGridData) {
        //扫描logic公式
        const logicFormulaCount = this.scanFormula(iGridData);
        console.log(`检测到逻辑公式，逻辑公式待执行数量为:${logicFormulaCount}`);
        if (logicFormulaCount > 0) {
            try {
                return await this.executeLogicFormula(iGridData);
            }
            catch (e) {
                throw e;
            }
        }
        else {
            return iGridData || null;
        }
    }
    //执行逻辑公式，并刷新表格
    async executeLogicFormulaAndReloadTable() {
        try {
            const logicData = await this.scanAndExecuteAllFormula();
            this.context.reloadTable(logicData);
        }
        catch (e) {
            throw e;
        }
    }
}
